%% Main Crazy Curl for MultiClass Classification %%%%%%%%%%%%%%%%%%%%%%%%%%
% 3/2013
% Marcelo Fiori, Guzman Hernandez, Alicia Fernandez and matias Di Martino.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% Set General parameters, 
%DataBaseName = 'DataSet2C2F'; %{'Iris','Generate'} letf in blank to generate data
verbose = 1; %(1 - display text, 2 - display text and charts)
fid = fopen('output.txt','a'); % logfile,
fprintf(fid,['\n \n =========================================================  \n ']);
fprintf(fid,['\t DataBaseName : ' DataBaseName]);
fprintf(fid,['\n =========================================================  \n ']);

% Set path
addpath ../toolboxs
addpath ../toolboxs/libsvm-3.17/matlab
addpath ../code

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 1) Generate/Load Data %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if verbose>0, fprintf('Generating/Loading data ... \n'), end

% /////////////////////////////////////////////////////////////////////////
% /// Chose database or generate data /////////////////////////////////////
% /////////////////////////////////////////////////////////////////////////

switch DataBaseName,
    case 'Iris',
        load('../bases/Iris/Iris.mat');
        Samples = Iris(:,1:4);
        Labels = Iris(:,5);
    case 'balance',
        load('../bases/balance.mat');
        Samples = balance(:,1:4);
        Labels = balance(:,5);
    case 'yeast',
        load('../bases/yeast.mat');
        Samples = yeast(:,1:8);
        Labels = yeast(:,9); 
    case 'Generate',
        % Define number of classes and dimensions
        NumberOfClasses = 5;
        NumberOfDimensions = 4;
        MaxNumberOfSamplesPerClass = 5000;
        [Samples,Labels] = GenerateData(NumberOfClasses,NumberOfDimensions, ...
            MaxNumberOfSamplesPerClass);
    otherwise,        
        load(['../bases/' DataBaseName]);        
end

NumberOfDimensions = size(Samples,2);
NumberOfClasses = max(Labels(:));
NumberOfSamples = size(Samples,1);
Dimensions = size(Samples,2);
% define colors for different clases, 
aux = colormap(jet(NumberOfClasses));
clear Colors
for c = 1:NumberOfClasses,
    Colors{c} = aux(c,:);
end

if verbose>0, 
    for class = 1:NumberOfClasses, 
        fprintf('Samples of class %d : %d \n',class,sum(Labels==class))
    end
    fprintf('\n')
end

% Normalization ---------------------------------------
for dim = 1:NumberOfDimensions,
    Samples(:,dim) = (Samples(:,dim) - min(Samples(:,dim))) ...
           / ( max(Samples(:,dim)) - min(Samples(:,dim)) );  
end
% -----------------------------------------------------

% 
% /////////////////////////////////////////////////////////////////////////
% //// Display ////////////////////////////////////////////////////////////
% /////////////////////////////////////////////////////////////////////////

if verbose>1 && NumberOfDimensions < 4;% Display Data,
    
    % Open new figure
    h = figure('name','Data','NumberTitle','off');
       
    if NumberOfDimensions==2,

        for class = 1:NumberOfClasses,
            scatter(Samples(Labels==class,1),Samples(Labels==class,2),...
                'CData',Colors{class}); hold on,
        end
    else
        for class = 1:NumberOfClasses,
            scatter3(Samples(Labels==class,1),Samples(Labels==class,2),...
                Samples(Labels==class,3),'CData',Colors{class}); hold on,
        end
    end
end 
% /////////////////////////////////////////////////////////////////////////

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 2) Split Data in train and test %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
TrainSamples = Samples([1:2:end],:);
TrainLabels = Labels([1:2:end]);
TestSamples = Samples([2:2:end],:);
TestLabels = Labels([2:2:end]);

if verbose>1 && NumberOfDimensions < 4;% Display Data,
    
    % Open new figure and display train samples
    h = figure('name','Training Samples','NumberTitle','off');       
    if NumberOfDimensions==2,
        for class = 1:NumberOfClasses,
            scatter(TrainSamples(TrainLabels==class,1),TrainSamples(TrainLabels==class,2),...
                'CData',Colors{class}); hold on,
        end
    else
        for class = 1:NumberOfClasses,
            scatter3(TrainSamples(TrainLabels==class,1),TrainSamples(TrainLabels==class,2),...
                     TrainSamples(TrainLabels==class,3),'CData',Colors{class}); hold on,
        end
    end
    
    % Open new figure and display test samples
    h = figure('name','Test Samples','NumberTitle','off');       
    if NumberOfDimensions==2,
        for class = 1:NumberOfClasses,
            scatter(TestSamples(TestLabels==class,1),TestSamples(TestLabels==class,2),...
                'CData',Colors{class}); hold on,
        end
    else
        for class = 1:NumberOfClasses,
            scatter3(TestSamples(TestLabels==class,1),TestSamples(TestLabels==class,2),...
                     TestSamples(TestLabels==class,3),'CData',Colors{class}); hold on,
        end
    end

end 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 3) Training Classifiers %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if verbose>0, fprintf('Training Classifiers ... \n'), end

ClassifiersName = {'CC','SVM','SVM-RBF'};
NumberOfClassifiers = length(ClassifiersName);

for Class = 1:NumberOfClassifiers,
    switch ClassifiersName{Class},
        % /////////////////////////////////////////////////////////////////
        case 'CC', % //////////////////////////////////////////////////////
        % /////////////////////////////////////////////////////////////////
            parameters.verbose=verbose; %{1 display some text, 2 also graphics}
            parameters.delta_t = 1e-2;
            parameters.tol = 0;
            parameters.max_iter = 500;
            maxPoints = 1e6; % {12825761~12e6} hasta este punto anda, pero un poco lento     
            parameters.GridSize = maxPoints^(1/NumberOfDimensions);
            parameters.Lambda0 = 0;
            parameters.Sigma = 0; % if Sigma = 0, the value is tuned 
                                     % automatically using 10 fold cv
            parameters.SigmaInterval = [10^-2 10^0]; % range in which sigma is tuned.
            parameters.RegularityCoef = 0;
           
            [U,X] = CC_Train_nd(TrainSamples,TrainLabels,parameters);
            
            % Save model, -----
            ClassifierModel{Class}.U = U;
            ClassifierModel{Class}.X = X;
            % -----------------
            
        % /////////////////////////////////////////////////////////////////
        case 'SVM', % /////////////////////////////////////////////////////
        % /////////////////////////////////////////////////////////////////
           % verbose = verbose; 
            Gamma = [0]; % if we use Gamma = 0; SVM_train use linear svm.
            Cost = [1e-2 200 10];
            SelectedMeasure = 'Gmean';
            [model] = SVM_train(TrainSamples,TrainLabels, [verbose], Gamma, Cost,SelectedMeasure);
            
            % Save model, -----
            ClassifierModel{Class} = model;
            % -----------------
        % /////////////////////////////////////////////////////////////////
        case 'SVM-RBF' % //////////////////////////////////////////////////
        % /////////////////////////////////////////////////////////////////
           % verbose = 1; 
            Gamma = [.1 50 10]; Cost = [1e-1 1e3 10];
            SelectedMeasure = 'Gmean';
            [model] = SVM_train(TrainSamples,TrainLabels, [verbose], Gamma, Cost,SelectedMeasure);
            
            % Save model, -----
            ClassifierModel{Class} = model;
            % -----------------
 
       otherwise error('Invalid Classifier name')
    end
end
    
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 4) Testing %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if verbose>0, fprintf('Testing ... \n'), end

for Class = 1:NumberOfClassifiers,
    switch ClassifiersName{Class},
        % /////////////////////////////////////////////////////////////////
        case 'CC', % //////////////////////////////////////////////////////
        % ///////////////////////////////////////////////////////////////// 
            U = ClassifierModel{Class}.U;
            X = ClassifierModel{Class}.X;
            clear parameters,
            parameters.verbose = verbose;
            [TestPredictedLabels{Class}] = CC_Classify_nd(TestSamples,U,X,parameters);
            [TrainPredictedLabels{Class}] = CC_Classify_nd(TrainSamples,U,X,parameters);
            % -------------------------------------------------------------
        % /////////////////////////////////////////////////////////////////
        case 'SVM', % /////////////////////////////////////////////////////
        % /////////////////////////////////////////////////////////////////
            model = ClassifierModel{Class};
            [TestPredictedLabels{Class}, ~, ~] = svmpredict_libsvm(0*TestLabels, ...
                TestSamples, model);
            [TrainPredictedLabels{Class}, ~, ~] = svmpredict_libsvm(0*TrainLabels, ...
                TrainSamples, model);
        % /////////////////////////////////////////////////////////////////
        case 'SVM-RBF' % //////////////////////////////////////////////////
        % /////////////////////////////////////////////////////////////////
            model = ClassifierModel{Class};
            [TestPredictedLabels{Class}, ~, ~] = svmpredict_libsvm(0*TestLabels, ...
                TestSamples, model);
            [TrainPredictedLabels{Class}, ~, ~] = svmpredict_libsvm(0*TrainLabels, ...
                TrainSamples, model);
 
        otherwise error('Invalid Classifier name')
    end
end



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 5) Display Results %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
fprintf('//////////////////////////////////////////////////////////// \n');
fprintf([' Results for database  ' DataBaseName '\n']);
fprintf('//////////////////////////////////////////////////////////// \n');
fprintf(fid,'//////////////////////////////////////////////////////////// \n');
fprintf(fid,[' Results for database  ' DataBaseName '\n']);
fprintf(fid,'//////////////////////////////////////////////////////////// \n');

for ClassifierIndex = 1:NumberOfClassifiers;
    Name = ClassifiersName{ClassifierIndex};
    TestPL = TestPredictedLabels{ClassifierIndex};
    [Gmean, Acc, AccClass] = Performance(TestLabels,TestPL);
    fprintf('TEST ------------------------------------------------\n');
    fprintf(fid,'TEST ------------------------------------------------\n');

    fprintf([Name '\n']);
    fprintf(fid,[Name '\n']);
    fprintf('\t Test Accuracy: %1.1f %% ',Acc*100);
    fprintf(fid,'\t Test Accuracy: %1.1f %% ',Acc*100);

    for c = 1:NumberOfClasses, 
        fprintf(' || %1.1f ', AccClass(c)*100);
        fprintf(fid,' || %1.1f ', AccClass(c)*100);
    end 
    fprintf('\n');
    fprintf(fid,'\n');
    
    fprintf('\t Test Gmean: %1.1f %% \n',Gmean*100);
    fprintf(fid,'\t Test Gmean: %1.1f %% \n',Gmean*100);

    fprintf('TRAIN -----------------------------------------------\n');
    fprintf(fid,'TRAIN -----------------------------------------------\n');

    TrainPL = TrainPredictedLabels{ClassifierIndex};
    [Gmean, Acc,AccClass] = Performance(TrainLabels,TrainPL);
    fprintf([Name '\n']);
    fprintf(fid,[Name '\n']);
    
    fprintf('\t Test Accuracy: %1.1f %% ',Acc*100);
    fprintf(fid,'\t Test Accuracy: %1.1f %% ',Acc*100);
    
    for c = 1:NumberOfClasses, 
        fprintf(' || %1.1f ', AccClass(c)*100);
        fprintf(fid,' || %1.1f ', AccClass(c)*100); 
    end 
    
    fprintf('\n');
    fprintf(fid,'\n');
    
    fprintf('\t Train Gmean: %1.1f %% \n',Gmean*100);
    fprintf(fid,'\t Train Gmean: %1.1f %% \n',Gmean*100);
   
    if verbose>1 & NumberOfDimensions == 2,         
        % Plot samples and labels, 
        figure('name',['Predicted Labels for ' Name]),
        for class = 1:NumberOfClasses,
            scatter(TestSamples(TestPL==class,1),TestSamples(TestPL==class,2), ...
                'CData',Colors{class}); hold on
        end
        
        % Plot errors, 
        figure('name',['Accuracy for ' Name]),
        scatter(TestSamples(TestPL==TestLabels,1),TestSamples(TestPL==TestLabels,2), ...
                'CData',[0 1 0]); hold on
        scatter(TestSamples(TestPL~=TestLabels & TestPL~=0,1),...
                TestSamples(TestPL~=TestLabels & TestPL~=0,2), ...
               'CData',[1 0 0]); hold on
        scatter(TestSamples(TestPL==0,1),...
                TestSamples(TestPL==0,2), ...
               'CData',[0 0 1]); hold on      
    end
end

fclose('all');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


